import { assert, JsonAsset, Vec3 } from "cc";
import { Engine } from "../../core/Engine";
import Logger from "../../core/utils/Logger";
import { getNetTime, getNowTime } from "../../core/utils/utils";
import { DATA_NAME, DATA_OPTION, DATA_PROPERTY, EVENT_NAME, GAME_DATA, TIMER_TASK_TAG } from "../GameConstant";
import { gameRecordManager, GAME_ACCOUNT_KEY, PLAYER_STORAGE_KEY } from "../manager/GameRecordManager";
import { BaseData } from "./BaseData";
import { dataManager } from "./DataManager";
import { emenyAI } from "./EnemyAI";
import { BELONG_TYPE } from "./MapData";
import { DispatchArmyInfo } from "./SoldierData";

/**
 * Predefined variables
 * Name = EnemyData
 * DateTime = Sun Dec 19 2021 00:07:38 GMT+0800 (中国标准时间)
 * Author = han2007happy
 * FileBasename = EnemyData.ts
 * FileBasenameNoExtension = EnemyData
 * URL = db://assets/scripts/game/data/EnemyData.ts
 * ManualUrl = https://docs.cocos.com/creator/3.3/manual/en/
 *
 */
export class EnemyData extends BaseData {
    dataName = DATA_NAME.ENEMY_DATA;
    // 玩家数据
    buildList: { [cityId: string]: { id: string; cfgId: string } } = {};
    resourceList: { [materialId: string]: number } = {};
    soldierList: { [soldierId: string]: number } = {};

    dispatchingArmyList: {
        [armyId: string]: DispatchArmyInfo;
    } = {}; // 出征队列

    protected STORE_KEYS = {
        STORE_BUILD_LIST: PLAYER_STORAGE_KEY.STORE_ENEMY_BUILD_LIST,
        STORE_RESOURCE_LIST: PLAYER_STORAGE_KEY.STORE_ENEMY_RESOURCE_LIST,
        STORE_DISPATCH_ARMY_LIST: PLAYER_STORAGE_KEY.STORE_ENEMY_DISPATCH_ARMY_LIST,
    };

    // 已无军粮，自杀吧
    private waitKillSoldierIds: string[] = [];

    protected init() {
        super.init();
    }

    public async initData() {
        // 初始 资源
        this.buildList = {};
        this.resourceList = { ["material-1"]: 100, ["material-2"]: 100 }; // 初始 资源
        const storyBuildListStr = gameRecordManager.getPlayerDataByKey(this.STORE_KEYS.STORE_BUILD_LIST);
        if (storyBuildListStr) {
            this.buildList = JSON.parse(storyBuildListStr);
        }

        const resourceListStr = gameRecordManager.getPlayerDataByKey(this.STORE_KEYS.STORE_RESOURCE_LIST);
        if (resourceListStr) {
            this.resourceList = JSON.parse(resourceListStr);
        }

        const armyListStr = gameRecordManager.getPlayerDataByKey(this.STORE_KEYS.STORE_DISPATCH_ARMY_LIST);
        if (armyListStr) {
            this.dispatchingArmyList = JSON.parse(armyListStr);
        }

        emenyAI.init();
    }

    // 出征状态的士兵
    getDispatchArmySoldiers() {
        let soldiers: { [soldierId: string]: number } = {};
        for (const armyId in this.dispatchingArmyList) {
            const armyInfo = this.dispatchingArmyList[armyId];
            for (const soldierId in armyInfo.soldiers) {
                const soldierQuantity = armyInfo.soldiers[soldierId];
                soldiers[soldierId] = soldiers[soldierId] ?? 0 + soldierQuantity;
            }
        }
        return soldiers;
    }

    // 建造建筑
    public addBuilding(cityId: string, buildCfgId: string) {
        const buildCfgData: Building = dataManager.dataMap.getBuildCfg(buildCfgId)!;
        const fitResCondition = this.changePlayerResources(buildCfgData.costMeterials, true); // 是否满足资源条件
        if (fitResCondition) {
            this.buildList[cityId] = { id: Date.now() + "", cfgId: buildCfgId };
            gameRecordManager.setPlayerDataByKey(this.STORE_KEYS.STORE_BUILD_LIST, this.buildList);
            Engine.eventManager.emit(EVENT_NAME.BUILDING_ON_CITY, cityId, buildCfgId);
        }
        return fitResCondition;
    }

    // 移除建筑
    removeBuilding(cityId: string) {
        if (this.buildList[cityId]) {
            delete this.buildList[cityId];
            gameRecordManager.setPlayerDataByKey(this.STORE_KEYS.STORE_BUILD_LIST, this.buildList);

            Engine.eventManager.emit(EVENT_NAME.REMOVE_BUILDING_ON_CITY, cityId);
        }
    }

    // 修改士兵信息
    changeSoldiers(soldierId: string, changeValue: number) {
        // 玩家士兵信息修改
        const originNum = this.soldierList[soldierId] ? this.soldierList[soldierId] : 0;
        const currentNum = Number(originNum) + changeValue;
        if (currentNum === 0) {
            delete this.soldierList[soldierId];
        } else {
            this.soldierList[soldierId] = originNum + changeValue;
            if (this.soldierList[soldierId] < 0) {
                Logger.error("changeSoldiers:", soldierId, this.soldierList[soldierId]);
            }
        }
    }

    // 出兵，士兵队列
    async addDispatchingArmy(armyId: string, armyInfo: DispatchArmyInfo) {
        this.dispatchingArmyList[armyId] = armyInfo;
        gameRecordManager.setPlayerDataByKey(this.STORE_KEYS.STORE_DISPATCH_ARMY_LIST, this.dispatchingArmyList);
    }

    // 移除出兵队列
    removeDispatchingArmy(armyId: string) {
        delete this.dispatchingArmyList[armyId];
        gameRecordManager.setPlayerDataByKey(this.STORE_KEYS.STORE_DISPATCH_ARMY_LIST, this.dispatchingArmyList);
        gameRecordManager.setPlayerDataImmediately();
    }

    // 修正玩家资源数量
    changePlayerResource(materialId: string, changeVal: number) {
        const changeAfterVal = this.resourceList[materialId] ? this.resourceList[materialId] + changeVal : changeVal;
        if (changeAfterVal >= 0) {
            this.resourceList[materialId] = changeAfterVal;
        }
        return changeAfterVal >= 0;
    }

    // 修改玩家资源数量
    changePlayerResources(materials: { [materialId: string]: number }, isReduce: boolean = false) {
        let allResourcesFit = true;
        for (const materialId in materials) {
            const materialVal = isReduce ? -materials[materialId] : materials[materialId];
            const changeAfterVal = this.resourceList[materialId]
                ? this.resourceList[materialId] + materialVal
                : materialVal;
            if (changeAfterVal < 0) {
                allResourcesFit = false;
            }
        }
        if (allResourcesFit) {
            for (const materialId in materials) {
                const materialVal = isReduce ? -materials[materialId] : materials[materialId];
                this.changePlayerResource(materialId, materialVal);
            }
            Engine.eventManager.emit(this.buildEventName(DATA_OPTION.UPDATE, DATA_PROPERTY.materialS));
        }
        return allResourcesFit;
    }

    //  ------------- 定时调用 ------------------
    // 资源增长 10s增长值
    preFrameAddResource(dt: number) {
        // 建筑生成资源
        for (const cityId in this.buildList) {
            const buildData = this.buildList[cityId];
            const buildCfgData: Building = dataManager.dataMap.getBuildCfg(buildData.cfgId)!;
            for (const materialId in buildCfgData.outMeterials) {
                const materialOutVal = buildCfgData.outMeterials[materialId];
                if (materialId.startsWith("soldier-")) {
                    dataManager.dataMap.changeCitySoldiers(cityId, {
                        [materialId]: materialOutVal,
                    });
                } else {
                    this.changePlayerResource(materialId, materialOutVal);
                }
            }
        }

        // 士兵消耗资源
        for (const soldierId in this.soldierList) {
            const soldierNum = this.soldierList[soldierId];
            const soldierCfgData = dataManager.dataMap.getSoldierCfg(soldierId)!;
            for (const materialId in soldierCfgData.eatMeterials) {
                const materialEatVal = soldierCfgData.eatMeterials[materialId];
                if (this.resourceList[materialId] < materialEatVal * soldierNum) {
                    // 吃光粮草
                    this.changePlayerResource(materialId, -this.resourceList[materialId]);
                    this.waitKillSoldierIds.push(soldierId);
                } else {
                    this.changePlayerResource(materialId, -materialEatVal * soldierNum);
                }
            }
        }

        gameRecordManager.setPlayerDataByKey(this.STORE_KEYS.STORE_RESOURCE_LIST, this.resourceList);
        Engine.eventManager.emit(this.buildEventName(DATA_OPTION.UPDATE, DATA_PROPERTY.materialS));
    }

    // 粮草不够吃了，自杀一部分兵
    preSecondCheckKillSoldiers() {
        if (this.waitKillSoldierIds.length > 0) {
            dataManager.dataMap.lackResourceKillSoldiers(BELONG_TYPE.SELF_SIDE, this.waitKillSoldierIds);
            this.waitKillSoldierIds = [];
        }
    }

    // 每秒判断出征士兵当前位置并随时结束移动
    preFrameCheckSoldierArmy(dt: number) {
        for (const armyId in this.dispatchingArmyList) {
            const armyData = this.dispatchingArmyList[armyId]!;
            armyData.passTime += dt;
            armyData.currentCityPassTime += dt;
            const cityLine = dataManager.dataMap.getTwoCityLine(armyData.currentCityId, armyData.nextCityId);
            if (!cityLine) {
                console.error(" armyData:", armyData);

                return;
            }
            const moveToNextCityCostTime = cityLine.len / GAME_DATA.ARMY_SPEED;
            if (armyData.currentCityPassTime >= moveToNextCityCostTime) {
                armyData.currentCityId = armyData.nextCityId;
                const nextIdx = armyData.paths.indexOf(armyData.currentCityId) + 1;
                armyData.nextCityId = armyData.paths[nextIdx];
                armyData.currentCityPassTime = 0;
                if (dataManager.dataMap.getCityDetail(armyData.currentCityId)!.belong !== armyData.belong) {
                    // 途径城池归属发生改变，到此结束
                    dataManager.dataMap.stopDispatchArmy(
                        armyId,
                        armyData.fromCityId,
                        armyData.currentCityId,
                        armyData.belong
                    );
                    continue;
                }

                if (!armyData.nextCityId) {
                    // 到达终点，结束
                    dataManager.dataMap.stopDispatchArmy(
                        armyId,
                        armyData.fromCityId,
                        armyData.currentCityId,
                        armyData.belong
                    );
                    continue;
                }

                Engine.eventManager.emit(EVENT_NAME.ARMY_CHANGE_CURRENT_CITY, armyId, armyData);
            }
        }
    }
}
